package com.mygameframework.sprite;

import com.mygameframework.isoengine.TileSet;
import java.awt.Image;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Random;

/**
    The Animation class manages a series of images (frames) and
    the amount of time to display each frame.
*/
public abstract class TileSetAnimation implements Cloneable {
    protected TileSet tileSet;
    protected ArrayList<AnimFrame> frames;
//    protected  long totalDuration; //原书的,我废了
    /*
     * TODO 把Animation重构,让下面两变量归入sprite 中, 以便可以让多个精灵实列引用同一动画
     *
     */
    protected int currFrameIndex;
    protected long animTime;//游戏帧的时间叠加
    /*只有frames 浅复制,currFrameIndex和animTime 不进行克隆*/
    @Override
    public abstract Object clone();//{
//        return new Animation(frames, totalDuration);
    //}

    /**
        Creates a new, empty Animation.
    */
    protected TileSetAnimation(TileSet tileSet) {
        frames = new ArrayList();
        this.tileSet=tileSet;
//        totalDuration = 0;
        start();
    }
    protected TileSetAnimation(ArrayList frames,TileSet tileSet){
        this.frames=frames;
        this.tileSet=tileSet;
        start();
    }
    private String description;
    public void setDescription(String des){
        this.description=des;
    }
    @Override
    public String toString(){
        return description;
    }

    /**
        Adds an image to the animation with the specified
        duration (time to display the image).
    */
    public synchronized void addFrame(byte tileIdx,
        long duration)
    {
//        totalDuration += duration;
        AnimFrame aFrame= new AnimFrame(tileIdx, duration/*totalDuration*/);
        aFrame.setTsAnim(this);
        frames.add(aFrame);
    }


    /**
        Starts this animation over from the beginning.
    */
    public synchronized void start() {
        animTime = 0;
        currFrameIndex = 0;
    }
    //only reset sprite.currFrameIndex
    public synchronized void resetFrameIdx(){
        currFrameIndex = 0;
    }
//    public abstract void nextFrame(AbstractSprite sp,long elapsedTime);
    /**
        Updates this animation's current image (frame), if
        neccesary.
     * elapsedTime '游戏帧'所花费的时间
    */
    public synchronized void update(long elapsedTime) {
            if (frames.size() > 1) {
                /*原书Animation类的animTime是一段动画时间带中,当前在哪段时间,
                 * 我改为动画帧的时间带,当前在帧之间的哪段时间,
                 * 只是范围修窄,为了让Animation类更好扩展
                 * 现在 animTime 为'动画帧' 帧之间的时间
                 * 
                 * 即游戏帧的所花费时间的叠加 ,
                 * 加到一定程度,满足动画帧时间间隔要求,就进行下一动画帧
                 */ 
                animTime += elapsedTime;
                long interval=getFrame(currFrameIndex).interval;
                //while 而不用if,因为如果游戏帧花费太多时间,动画可以跳帧
                while(animTime>=getFrame(currFrameIndex).interval){
                    animTime-=getFrame(currFrameIndex).interval;
                    nextFrame();
                }
            
//                if (s.animTime >= totalDuration) {
//                    s.animTime = s.animTime % totalDuration;
//                    s.currFrameIndex = 0;
//                }
            //while 而不用if,因为如果游戏帧花费太多时间,动画可以跳帧
//            while (s.animTime > getFrame(s.currFrameIndex).interval) {
//                s.currFrameIndex++;
//            }
            }
    }


    /**
        Gets this Animation's current image. Returns null if this
        animation has no images.
    */
    public synchronized byte getCurrTileIdx() {
        return getCurrTileIdx(currFrameIndex);
    }

    public synchronized byte getCurrTileIdx(int frameIdx) {
        return getFrame(frameIdx).tileIdx;
    }
    public AnimFrame getCurrFrame(){
        return getFrame(currFrameIndex);
    }
    public AnimFrame getFrame(int idx) {
        if(frames.isEmpty()){
            return null;
        }else{
            return (AnimFrame)frames.get(idx);
        }
    }

    protected abstract void nextFrame();

    public static class Indexed extends TileSetAnimation{
        //如{2,3,5,1,4,6,7} 则第1动画帧是2帧,第2动画帧是3帧,第3是5 如此类推
        protected int[] indices;
        protected int arrayIdx;
        public Indexed(TileSet tileSet){
            super(tileSet);
            arrayIdx=0;
        }
        public Indexed(int[] idx,TileSet tileSet){
            super(tileSet);
            indices=new int[idx.length];
            System.arraycopy(idx, 0, indices, 0, idx.length);
            arrayIdx=0;
            start();
        }
        @Override
        protected void nextFrame() {
            if(frames==null||frames.isEmpty()) return;
            if(++arrayIdx>=indices.length){
                arrayIdx=0;
            }
            this.currFrameIndex=indices[arrayIdx];
        }

        private Indexed(ArrayList frames,int[] userIdx,TileSet tileSet) {
            super(frames,tileSet);
//            indices=new int[userIdx.length];
//            System.arraycopy(userIdx, 0, indices, 0, userIdx.length);
            this.indices=userIdx;
            arrayIdx=0;
//            super(frames);
        }
        
        @Override
        public Object clone() {
            return new Indexed(this.frames,this.indices,tileSet);
        }
        
    }
    public static class Looped extends TileSetAnimation{

        public Looped(TileSet tileSet) {
            super(tileSet);
        }

        private Looped(ArrayList frames,TileSet tileSet) {
            super(frames,tileSet);
        }
        
        @Override
        protected void nextFrame(){
            if(frames==null || frames.isEmpty()) return;
            if(++currFrameIndex>=frames.size()){
                resetFrameIdx();
            }
        }

        @Override
        public Object clone() {
            return new Looped(this.frames,tileSet);
        }
        
    }
    public static class OneShot extends TileSetAnimation{

        public OneShot(TileSet tileSet) {
            super( tileSet);
        }
        
        private OneShot(ArrayList frames,TileSet tileSet) {
            super(frames, tileSet);
        }
        
        @Override
        public Object clone() {
            return new OneShot(this.frames, tileSet);
        }

        @Override
        protected void nextFrame() {
            if(frames==null ||frames.isEmpty()
                    || currFrameIndex==(frames.size()-1))
                return;
            if(++currFrameIndex>=frames.size()){
                currFrameIndex=frames.size()-1;
            }
        }
        
    }
    public static class Single extends TileSetAnimation{

        private Single(ArrayList frames,TileSet tileSet) {
            super(frames, tileSet);
        }

        public Single(TileSet tileSet) {
            super(tileSet);
        }

        @Override
        public Object clone() {
            return new Single(frames, tileSet);
        }

        @Override
        public synchronized void update(long elapsedTime) {
            //什么也不用做
        }

        @Override
        protected void nextFrame() {
            //什么也不用做
        }
        
    }
    public static class Rnd extends TileSetAnimation{
        private Random rnd;
        private Rnd(ArrayList frames,TileSet tileSet) {
            super(frames,tileSet);
            rnd=new Random();
        }

        public Rnd(TileSet tileSet) {
            super(tileSet);
            rnd=new Random();
        }

        @Override
        public Object clone() {
            return new Rnd(frames, tileSet);
        }

        @Override
        protected void nextFrame() {
            if(frames==null||frames.size()<=1) return;
            currFrameIndex=rnd.nextInt(frames.size());
        }
        
    }
    public class AnimFrame {

        byte tileIdx;
        long interval;
        Rectangle extent;
        TileSetAnimation tsAnim;

        public AnimFrame(byte tileIdx, long interval) {
            this.tileIdx = tileIdx;
            this.interval = interval;
//            extent=new Rectangle(image.getWidth(null), image.getHeight(null));
        }

        public TileSetAnimation getTsAnim() {
            return tsAnim;
        }

        public void setTsAnim(TileSetAnimation tsAnim) {
            this.tsAnim = tsAnim;
        }
        
        public int getFrameWidth(){
            return this.tsAnim.tileSet.getInfos()[tileIdx].dstExt.width;
        }
        public int getFrameHeight(){
            return this.tsAnim.tileSet.getInfos()[tileIdx].dstExt.height;
        }
        /***
         * 返回 TileSet.getInfos()[当前帧相应的tile索引值].dstExt
         * @return 返回含有anchor的Rectangle
         */
        public Rectangle getDstExt(){
            return this.tsAnim.tileSet.getInfos()[tileIdx].dstExt;
        }
    }
}

